from webob import Response
from webob.exc import HTTPMovedPermanently
from fusion.http.controllers import BaseController
from fusion.db.exceptions import Unauthorized
from fusion.db.profile import Profile

class Admin(BaseController):
    def __init__(self):
        super(Admin, self).__init__()

    def index(self, req):
        # test to see if we have a persona
        v = {}
        db = req.environ['fusion.db']
        v['safety_color'] = db.get_safety_color()

        try:
            iid = db.get_my_iid()
            db.fetch(iid, '')
        except LookupError: # persona not initialized
            # redirect to admin
            redir_url = 'http://admin.hexlabel.net/setup_persona/'
            return HTTPMovedPermanently(location=redir_url)


        # proceed as normal
        view = self.load_view('admin.html')
        if view:
            v['path'] = req.host

            return view.render(**v)
        else:
            return None


    def import_persona(self, req):
        if req.method == 'POST':
            v = {}
            db = req.environ['fusion.db']
            v['safety_color'] = db.get_safety_color()

            # import persona
            if not req.POST.has_key('code') or not req.POST['code']:
                v['code'] = ''
                v['errors'] = True
                v['message'] = 'Please enter a code'

            elif not req.POST.has_key('passphrase') or not req.POST['passphrase']:
                v['code'] = req.POST['code']
                v['errors'] = True
                v['message'] = 'Please enter a password'

            else:
                try:
                    db.set_persona_from_code(req.POST['code'], req.POST['passphrase'])

                    # redirect to profile page
                    redir_url = 'http://my.hexlabel.net/'
                    return HTTPMovedPermanently(location=redir_url)

                except LookupError:
                    v['code'] = req.POST['code']
                    v['errors'] = True
                    v['message'] = 'No such account'
                except Exception, e:
                    v['code'] = req.POST['code']
                    v['errors'] = True
                    v['message'] = 'Connection error. Please try again later. (%s)' % e

            view = self.load_view('admin.import_persona.html')
            if view:
                # engage -->
                return view.render(**v)
            else:
                return None

        else:
            view = self.load_view('admin.import_persona.html')

            if view:
                v = {}
                db = req.environ['fusion.db']
                v['safety_color'] = db.get_safety_color()
                v['code'] = ''
                v['errors'] = False
                v['message'] = ''

                # engage -->
                return view.render(**v)
            else:
                return None


    def setup_persona(self, req):
        if req.method == 'POST':
            v = {}
            db = req.environ['fusion.db']
            v['safety_color'] = db.get_safety_color()

            try:
                # make sure no persona exists
                iid = db.get_my_iid()
                db.fetch(iid, '')

                # get current user iid and redirect
                redir_url = 'http://%s.hexlabel.net/person/' % iid
                return HTTPMovedPermanently(location=redir_url)
            except LookupError: # persona not initialized
                pass

            # create new persona
            v['name'] = req.POST['name']
            if not req.POST.has_key('name') or not req.POST['name']:
                v['errors'] = True
                v['message'] = 'Please enter a name'

                view = self.load_view('admin.setup_persona.html')
                if view:
                    # engage -->
                    return view.render(**v)
                else:
                    return None

            else:
                iid = db.create_persona()
                profile = Profile()
                profile.name = req.POST['name']
                profile.write(db, iid)

                # redirect to profile page
                redir_url = 'http://%s.hexlabel.net/person/' % iid
                return HTTPMovedPermanently(location=redir_url)

        else:
            # GET
            view = self.load_view('admin.setup_persona.html')

            if view:
                v = {}
                v['errors'] = False
                v['message'] = ''

                # engage -->
                return view.render(**v)
            else:
                return None


    def personal_code(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.personal_code.html')

            if view:
                v = {}
                db = req.environ['fusion.db']
                v['safety_color'] = db.get_safety_color()

                if req.POST['passphrase'] != req.POST['passphrase_confirm']:
                    v['errors'] = True
                    v['message'] = 'Password and Password confirm do not match'
                elif not req.POST['passphrase']:
                    v['errors'] = True
                    v['message'] = 'Password cannot be empty'

                else:
                    v['code'] = db.reset_personal_code(req.POST['passphrase'])
                    v['errors'] = False
                    v['message'] = "Passphrase set"

                return view.render(**v)
            else:
                return None

        else:
            view = self.load_view('admin.personal_code.html')

            if view:
                v = {}
                db = req.environ['fusion.db']
                v['safety_color'] = db.get_safety_color()
                v['errors'] = False
                v['message'] = ''

                return view.render(**v)
            else:
                return None


    def invitations(self, req):
        view = self.load_view('admin.invitations.html')

        if view:
            v = {}
            db = req.environ['fusion.db']
            v['safety_color'] = db.get_safety_color()

            if not self._invitations_awake:
                self._wake_invitations_rep(db)

            v['my_iid'] = db.get_my_iid()
            v['invitations'] = None
            v['errors'] = False
            v['message'] = ''
            v['errors_pending'] = False
            v['message_pending'] = ''
            v['errors_friends'] = False
            v['message_friends'] = ''
            v['errors_groups'] = False
            v['message_groups'] = ''
            v['friend_list'] = self._process_friend_list(db, v['my_iid'])
            v['group_list'] = self._process_group_list(db, v['my_iid'])

            v['invitecode'] = ''
            if req.params.has_key('do'):
                if req.params['do'] == 'revoke_group':
                    if req.method == 'POST':
                        if req.POST.has_key('iid') and req.POST['iid']:
                            v['iid'] = req.POST['iid']
                            db.cancel_membership(v['iid'])
                            v['errors_groups'] = False
                            v['message_groups'] = 'Membership resigned'
                            v['invitations'] = self._get_invitations(db)
                            v['friend_list'] = self._process_friend_list(db, v['my_iid'])
                            v['group_list'] = self._process_group_list(db, v['my_iid'])
                            return view.render(**v)
                        else:
                            # ERROR no iid
                            v['invitations'] = self._get_invitations(db)
                            v['errors_groups'] = True
                            v['message_groups'] = 'No iid given'
                            return view.render(**v)
                    else:
                        # ERROR not post
                        pass

                if req.params['do'] == 'revoke_friend':
                    if req.method == 'POST':
                        if req.POST.has_key('iid') and req.POST['iid']:
                            v['iid'] = req.POST['iid']
                            db.revoke_friendship(v['iid'])
                            v['errors_friends'] = False
                            v['message_friends'] = 'Friendship revoked'
                            v['invitations'] = self._get_invitations(db)
                            v['friend_list'] = self._process_friend_list(db, v['my_iid'])
                            v['group_list'] = self._process_group_list(db, v['my_iid'])
                            return view.render(**v)
                        else:
                            # ERROR no iid
                            v['invitations'] = self._get_invitations(db)
                            v['errors_friends'] = True
                            v['message_friends'] = 'No iid given'
                            return view.render(**v)
                    else:
                        # ERROR not post
                        pass


                if req.params['do'] == 'decide':
                    if req.method == 'POST':
                        if req.POST.has_key('invitation_iid') and req.POST['invitation_iid']:
                            v['iid'] = req.POST['invitation_iid']
                            if self._transient_invitations.has_key(v['iid']):


                                decision = req.POST.get('invitation_accept')
                                if (decision):
                                    result = self._transient_invitations[v['iid']]['invitation'].accept_new(db)
                                    if result == 'OK':
                                        # ACCEPT
                                        self._delete_invitation(db, v['iid'])
                                        v['invitations'] = self._get_invitations(db)
                                        v['errors_pending'] = False
                                        v['message_friends'] = 'Invitation accepted'
                                        v['invitations'] = self._get_invitations(db)
                                        v['friend_list'] = self._process_friend_list(db, v['my_iid'])
                                        v['group_list'] = self._process_group_list(db, v['my_iid'])
                                        return view.render(**v)
                                    else:
                                        # ERROR could not accept
                                        v['invitations'] = self._get_invitations(db)
                                        v['errors_pending'] = True
                                        v['message_pending'] = 'Unable to accept invitation'
                                        return view.render(**v)

                                decision = req.POST.get('invitation_decline')
                                if (decision):
                                    # DECLINE
                                    self._delete_invitation(db, v['iid'])
                                    v['invitations'] = self._get_invitations(db)
                                    v['errors_pending'] = False
                                    v['message_pending'] = 'Invitation declined'
                                    return view.render(**v)

                            else:
                                # ERROR no such invitation
                                print "KONK5"
                                v['invitations'] = self._get_invitations(db)
                                v['errors_pending'] = True
                                v['message_pending'] = 'No such invitation'
                                return view.render(**v)
                        else:
                            # ERROR no iid
                            v['invitations'] = self._get_invitations(db)
                            v['errors_pending'] = True
                            v['message_pending'] = 'No iid given'
                            return view.render(**v)
                    else:
                        # ERROR not post
                        pass
                                

                if req.params['do'] == 'entercode':
                    # deal with invite code entry
                    v['do_in'] = req.params['do']
                    if req.params.has_key('invitecode') and req.params['invitecode']:
                        v['invitecode'] = req.params['invitecode'].strip()
                        try:
                            invitation = db.fetch_invitation(v['invitecode'])
                        except LookupError:
                            v['invitations'] = self._get_invitations(db)
                            v['errors'] = True
                            v['message'] = 'Connection error. Please try again later.'
                            return view.render(**v)
                        except:
                            v['invitations'] = self._get_invitations(db)
                            v['errors'] = True
                            v['message'] = 'Protocol error (what is that?). Please try again later.'
                            return view.render(**v)
            
                        if not invitation:
                            v['invitations'] = self._get_invitations(db)
                            v['errors'] = True
                            v['message'] = 'No such invitation code.'
                            return view.render(**v)
            
                        elif invitation.iid == db.get_my_iid():
                            v['invitations'] = self._get_invitations(db)
                            v['errors'] = True
                            v['message'] = 'Invitation code was created by you and is now removed'
                            return view.render(**v)

                        elif v['friend_list']['items'].has_key(invitation.iid):
                            v['invitations'] = self._get_invitations(db)
                            v['errors'] = True
                            v['message'] = 'This person (<a href="http://%s.hexlabel.net/">%s</a>) is already your friend' % (invitation.iid, v['friend_list']['items'][invitation.iid]['name'])
                            return view.render(**v)
            
                        else:
                            self._add_invitation(db, invitation, v['invitecode'])
                            db.subscribe(invitation.iid)
                            v['invitations'] = self._get_invitations(db)
                            v['errors'] = False
                            v['message_pending'] = 'Invitation is pending'
                            v['invitecode'] = ''
                            return view.render(**v)

                    else:
                        v['invitations'] = self._get_invitations(db)
                        v['invitecode'] = ''
                        v['errors'] = True
                        v['message'] = 'Please enter an invitation code'
                        
                        return view.render(**v)

            v['invitations'] = self._get_invitations(db)
            v['errors'] = False
            v['message'] = ''

            return view.render(**v)
        else:
            return None


    def invite_person(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.invite_person.html')

            if view:
                v = {}
                db = req.environ['fusion.db']
                v['safety_color'] = db.get_safety_color()

                v['code'] = db.create_friendship_invitation_code()
                v['email'] = req.POST.get('email')
                v['from_iid'] = req.POST.get('from_iid')
                v['show_invitation'] = True

                return view.render(**v)
            else:
                return None

        else:
            # GET
            view = self.load_view('admin.invite_person.html')

            if view:
                v = {}
                db = req.environ['fusion.db']
                v['safety_color'] = db.get_safety_color()
                v['show_invitation'] = False

                return view.render(**v)
            else:
                return None


    def invite_group_list(self, req):
        view = self.load_view('admin.invite_group_list.html')

        if view:
            v = {}
            db = req.environ['fusion.db']
            v['safety_color'] = db.get_safety_color()
            v['my_iid'] = db.get_my_iid()
            v['group_list'] = self._process_group_list(db, v['my_iid'])

            return view.render(**v)
        else:
            return None


    def invite_group(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.invite_group.html')

            if view:
                v = {}
                db = req.environ['fusion.db']
                v['safety_color'] = db.get_safety_color()

                v['email'] = req.POST.get('email')
                v['iid'] = req.POST.get('iid')
                if not v['iid']:
                    return None

                gprofile = Profile()
                gprofile.read(db, v['iid'])
                v['profile_fields'] = self._process_group_profile(db, gprofile, v['iid'])

                v['code'] = db.create_membership_invitation_code(v['iid'])
                v['show_invitation'] = True

                return view.render(**v)
            else:
                return None

        else:
            # GET
            view = self.load_view('admin.invite_group.html')

            if view:
                v = {}
                db = req.environ['fusion.db']
                v['safety_color'] = db.get_safety_color()
                v['iid'] = req.GET.get('iid')
                if not v['iid']:
                    return None


                gprofile = Profile()
                gprofile.read(db, v['iid'])
                v['profile_fields'] = self._process_group_profile(db, gprofile, v['iid'])

                v['show_invitation'] = False

                return view.render(**v)
            else:
                return None
        
        

    def create_group(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.create_group.html')

            if view:
                v = {}
                db = req.environ['fusion.db']

                v['safety_color'] = db.get_safety_color()
                v['errors'] = False
                v['message'] = ''
                v['my_iid'] = db.get_my_iid()

                # get the generic fields
                generic_fields = set([(key,val) for key,val in req.POST.items() if key.startswith('generic')])

                #[TODO: convert to dictionaries no good?]
                generic_fields = dict(generic_fields)

                # update name
                if not generic_fields.get('generic#0#name'):
                # get raw profile obj
                    profile = Profile()
                    v['profile'] = profile
                    v['profile_fields'] = self._process_group_profile(db, profile)
                    v['profile_fields']['generic']['about']['values'][0]['value'] = generic_fields.get('generic#0#about')

                    v['errors'] = True
                    v['message'] = 'Please enter a name'
                    return view.render(**v)

                name = (generic_fields['generic#0#name'] or '').strip()


                # create group
                try:
                    iid = db.create_group(name)

                    if generic_fields.get('generic#0#about'):
                        profile = Profile()
                        profile.read(db, iid)

                        # update about
                        profile.set_about(generic_fields['generic#0#about'] or '', public=True)
                        profile.write(db, iid)

                except (Unauthorized, LookupError):
                    v['errors'] = True
                    v['message'] = 'Could not create group at this time.'
                    return view.render(**v)

                # redirect to profile
                redir_url = 'http://%s.hexlabel.net/group/' % iid
                return HTTPMovedPermanently(location=redir_url)
            else:
                return None

        else:
            # GET
            view = self.load_view('admin.create_group.html')

            if view:
                v = {}
                db = req.environ['fusion.db']

                v['safety_color'] = db.get_safety_color()
                v['errors'] = False
                v['message'] = ''
                v['my_iid'] = db.get_my_iid()

                # get raw profile obj
                profile = Profile()
                v['profile'] = profile
                v['profile_fields'] = self._process_group_profile(db, profile)

                # engage -->
                return view.render(**v)
            else:
                return None

        

    def manage_group(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.manage_group.html')

            if view:
                v = {}
                db = req.environ['fusion.db']
                v['safety_color'] = db.get_safety_color()
                v['errors'] = False
                v['message'] = ''
                v['my_iid'] = db.get_my_iid()
                v['iid'] = req.POST.get('iid')
                if not v['iid']:
                    return None

                # get multiple (checkbox) values
                v['miid_list'] = req.POST.getall('miid')

                gprofile = Profile()
                gprofile.read(db, v['iid'])
                v['profile_fields'] = self._process_group_profile(db, gprofile, v['iid'])
                v['member_list'] = self._process_member_list(db, v['iid'], v['my_iid'])
                
                v['is_member'] = v['my_iid'] in v['member_list']['index']
                v['is_admin'] = v['is_member'] and 'admin' in v['member_list']['items'][v['my_iid']]['roles']

                if v['is_admin']:
                    if len(v['miid_list']) > 0:
                        do = req.POST.get('grant_author')
                        if do:
                            for miid in v['miid_list']:
                                roles = db.get_roles(v['iid'], miid)
                                if not 'author' in roles:
                                    roles.append('author')

                                db.set_roles(v['iid'], miid, roles)

                            v['message'] = 'Author role granted'
                            v['member_list'] = self._process_member_list(db, v['iid'], v['my_iid'])
                            return view.render(**v)

                        do = req.POST.get('revoke_author')
                        if do:
                            for miid in v['miid_list']:
                                roles = db.get_roles(v['iid'], miid)
                                if 'author' in roles:
                                    roles = [x for x in roles if not x == 'author']

                                db.set_roles(v['iid'], miid, roles)

                            v['message'] = 'Author role revoked'
                            v['member_list'] = self._process_member_list(db, v['iid'], v['my_iid'])
                            return view.render(**v)

                        do = req.POST.get('grant_admin')
                        if do:
                            for miid in v['miid_list']:
                                roles = db.get_roles(v['iid'], miid)
                                if not 'admin' in roles:
                                    roles.append('admin')

                                db.set_roles(v['iid'], miid, roles)

                            v['message'] = 'Admin role granted'
                            v['member_list'] = self._process_member_list(db, v['iid'], v['my_iid'])
                            return view.render(**v)

                        do = req.POST.get('revoke_admin')
                        if do:
                            for miid in v['miid_list']:
                                roles = db.get_roles(v['iid'], miid)
                                if 'admin' in roles:
                                    roles = [x for x in roles if not x == 'admin']

                                db.set_roles(v['iid'], miid, roles)

                            if v['my_iid'] in v['miid_list']:
                                # revoked own admin role, re-direct
                                redir_url = 'http://admin.hexlabel.net/invitations/#groups'
                                return HTTPMovedPermanently(location=redir_url)

                            else:
                                v['message'] = 'Admin role revoked'
                                v['member_list'] = self._process_member_list(db, v['iid'], v['my_iid'])
                                return view.render(**v)

                        do = req.POST.get('revoke_membership')
                        if do:
                            for miid in v['miid_list']:
                                roles = db.revoke_membership(v['iid'], miid)

                            v['message'] = 'Membership revoked'
                            v['member_list'] = self._process_member_list(db, v['iid'], v['my_iid'])
                            return view.render(**v)

                    else:
                        v['errors'] = True
                        v['message'] = 'No members selected'
                        return view.render(**v)
                        
                else:
                    v['errors'] = True
                    v['message'] = 'Permission denied (%s)' % v['is_member']

                return view.render(**v)

        else:
            # GET
            v = {}
            db = req.environ['fusion.db']
            v['safety_color'] = db.get_safety_color()
            v['my_iid'] = db.get_my_iid()
            v['iid'] = req.GET.get('iid')
            if not v['iid']:
                return None

            gprofile = Profile()
            gprofile.read(db, v['iid'])
            v['profile_fields'] = self._process_group_profile(db, gprofile, v['iid'])
            v['member_list'] = self._process_member_list(db, v['iid'], v['my_iid'])
            
            v['is_member'] = v['my_iid'] in v['member_list']['index']
            v['is_admin'] = v['is_member'] and 'admin' in v['member_list']['items'][v['my_iid']]['roles']

            if v['is_admin']:
                view = self.load_view('admin.manage_group.html')
            else:
                view = self.load_view('admin.permission_denied.html')

            if view:
                return view.render(**v)
            else:
                return None



    def browse_db(self, req):
            # GET
            v = {}
            db = req.environ['fusion.db']
            v['safety_color'] = db.get_safety_color()
            v['my_iid'] = db.get_my_iid()

            v['dataset_list'] = self._process_all_datasets(db)
            v['dataset_iid'] = None

            # get path info if any
            pi = req.path
            if pi:
                pi_segements = pi[1:].split('/')
                v['dataset_iid'] = pi_segements[1]
                v['dataset_path'] = '/'.join(pi_segements[2:])
                v['dataset'] = self._process_dataset(db, v['dataset_iid'])


            view = self.load_view('admin.browse_db.html')
            if view:
                return view.render(**v)
            else:
                return None


